/*
 * channel.hpp
 *
 *  Created on: Nov 27, 2011
 *      Author: ludmilla
 */

#ifndef CHANNEL_HPP_
#define CHANNEL_HPP_

# include <boost/exception/all.hpp>
# include <boost/shared_ptr.hpp>
# include <queue>

typedef int error_code_t;


class channel_invalid_state;

enum channel_state_t {
	initial = 0,
	opened = 1,
	closed = 2,
	error_ = 99
};

class ChannelState {
	channel_state_t				state;
	error_code_t	err_num;
public :
	void setInitiated () {state = initial;}
	void setOpened () {state = opened;}
	void setClosed () {state = closed;}
	void setError (error_code_t en) {state = error_; err_num = en;}

	bool operator == (channel_state_t s) {return state == s;}
	bool operator != (channel_state_t s) {return state != s;}

	std::string getStateForName () {
		switch (state) {
		case initial :
			return std::string ("initial");
			break;
		case opened :
			return std::string ("opened");
			break;
		case closed :
			return std::string ("closed");
			break;
		case error_ :
			return std::string ("error");
			break;
		default :
			return std::string ("undefined");
		}
	}
};

class Message {

};

//interface for channels
class channel_interface  {
protected :
	virtual void doOpen () = 0;
	virtual void doClose () = 0;
	virtual Message const & doRead () = 0;
	virtual void doWrite (Message const &) const = 0;
	channel_interface () {}
	~channel_interface () {};
};

// abstract class for channels
template <class State>
class channel : public channel_interface {
protected :
	State s;
	std::queue<Message> rq;

	virtual ~channel () {}
public :
	channel () {}
	void open () {
		if (this->getState() != initial || getState() != closed) {
			throw channel_invalid_state ();
		}
		this->doOpen ();
		s.setOpened ();
	}
	void close () {
		this->doClose ();
	}
	Message const & read () {
		return this->doRead ();
	}
	void write (Message const &m) {
		this->doWrite (m);
	}

	State getState() {return s;}

};

class channel_invalid_state : public boost::exception {
//protected :
//	inline std::string getString ()
//	{
//		std::stringstream ss;
//		ss << "Channel state " << ch->getState().getStateForName() << std::endl;
//		return ss.str ();
//	}
public :
	channel_invalid_state ()
	{
	}
	~channel_invalid_state () throw () {};
};


#endif /* CHANNEL_HPP_ */
